//
//  ZLPopMenu.swift
//  ZLPopMenu
//
//  Created by 赵振磊 on 2025/1/11.
//

import UIKit
import SnapKit

public enum ZLPopMenuDirection {
    case horizontal  // 水平
    case vertical   // 竖直
}

public enum ZLPopMenuPosition {
    case top
    case bottom
}

public class ZLPopMenu: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
    
    // 箭头视图
    private lazy var arrowView: UIView = {
        let view = UIView(frame: CGRect(x: 0, y: 0, width: 12, height: 6))
        let subLayer = CAShapeLayer()
        subLayer.frame = view.bounds
        subLayer.fillColor = UIColor(hex: "#f4f4f4").cgColor
        
        let path = UIBezierPath()
        let point1 = CGPoint(x: 0, y: 6)
        let point2 = CGPoint(x: 6, y: 0)
        let point3 = CGPoint(x: 12, y: 6)
        path.move(to: point1)
        path.addLine(to: point2)
        path.addLine(to: point3)
        path.move(to: point1)
        path.lineCapStyle = .round
        subLayer.path = path.cgPath
        view.layer.insertSublayer(subLayer, at: 0)
        return view
    }()
    
    // 内容视图
    private lazy var contentView: UIView = {
        let view = UIView()
        view.backgroundColor = UIColor(hex: "#f4f4f4")
        view.layer.cornerRadius = 5
        return view
    }()
    
    // 其他属性
    private weak var targetView: UIView?
    private var direction: ZLPopMenuDirection = .horizontal
    private var items: [ZLPopMenuItem] = []
    private var onCancel: (() -> Void)?
    private var maxWidth: CGFloat = 0
    
    // CollectionView 相关
    private lazy var collectionView: UICollectionView = {
        let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
        cv.backgroundColor = .clear
        cv.showsVerticalScrollIndicator = false
        cv.showsHorizontalScrollIndicator = false
        cv.delegate = self
        cv.dataSource = self
        cv.contentInset = UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
        cv.register(ZLPopMenuCell.self, forCellWithReuseIdentifier: "ZLPopMenuCell")
        return cv
    }()
    
    private lazy var layout: UICollectionViewFlowLayout = {
        let layout = UICollectionViewFlowLayout()
        layout.itemSize = CGSize(width: 60, height: 40)
        layout.minimumLineSpacing = 0
        layout.minimumInteritemSpacing = 0
        return layout
    }()
    
    public init(direction: ZLPopMenuDirection = .horizontal) {
        self.direction = direction
        super.init(nibName: nil, bundle: nil)
        self.modalPresentationStyle = .overFullScreen
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override public func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = .clear
        self.view.layer.shadowColor = UIColor(hex: "#333333").cgColor
        self.view.layer.shadowOffset = CGSize.zero
        self.view.layer.shadowOpacity = 0.2
        
        view.addSubview(arrowView)
        view.addSubview(contentView)
        contentView.addSubview(collectionView)
    }
    
    func updateUI() {
        guard let targetView = targetView else { return }
        let frame = targetView.convert(targetView.bounds, to: UIApplication.shared.keyWindow)
        let targetCenter = frame.origin.x + frame.size.width / 2.0
        var width: CGFloat = 0
        var height: CGFloat = ZLLineHeight
        
        if direction == .horizontal {
            width = 10
            for item in items {
                width += (item.itemSize.width + 10)
            }
            width = min(width, UIScreen.main.bounds.width - 10)
            layout.scrollDirection = .horizontal
            layout.minimumInteritemSpacing = 10
        } else {
            for item in items {
                width = max(item.itemSize.width, width)
            }
            maxWidth = width
            width = width + 20
            height = min(height * CGFloat(items.count),
                        UIScreen.main.bounds.height - frame.maxY - 50)
            layout.scrollDirection = .vertical
            layout.minimumInteritemSpacing = 0
        }
        
        var left = targetCenter - width / 2.0
        if (left + width) > UIScreen.main.bounds.width - 5 {
            left = UIScreen.main.bounds.width - width - 5
        } else if left < 5 {
            left = 5
        }
        
        arrowView.snp.remakeConstraints { make in
            make.left.equalTo(frame.midX - arrowView.bounds.width / 2.0)
            make.top.equalTo(frame.maxY)
            make.width.equalTo(12)
            make.height.equalTo(6)
        }
        
        contentView.snp.remakeConstraints { make in
            make.top.equalTo(arrowView.snp.bottom)
            make.left.equalTo(left)
            make.width.equalTo(width)
        }
        collectionView.snp.remakeConstraints { make in
            make.edges.equalToSuperview()
            make.height.equalTo(height)
        }
        
        collectionView.reloadData()
    }

    override public func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touch = touches.first else { return }
        let touchPoint = touch.location(in: view)
        
        if contentView.frame.contains(touchPoint) {
            super.touchesBegan(touches, with: event)
            return
        }
        
        dismiss(animated: false) {
            self.onCancel?()
        }
    }
    
    @discardableResult
    public func addItem(title: String,
                        color: UIColor = UIColor(red: 51, green: 51, blue: 51, alpha: 1),
                        font: UIFont = UIFont.systemFont(ofSize: 16),
                        callBack: @escaping () -> Void) -> Self {
        let item = ZLPopMenuItem(title: title, color: color, font: font, callBack: callBack)
        self.items.append(item)
        self.updateUI()
        return self
    }
    
    public func show(by view: UIView,
                     onClick: ((Int) -> Void)? = nil,
                     onCancel: (() -> Void)? = nil) {
        self.targetView = view
        self.onCancel = onCancel
        guard let topVC = ZLPopMenu.topViewController() else { return }
        topVC.present(self, animated: false)
    }
}

extension ZLPopMenu {
    public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let item = items[indexPath.row]
        if direction == .vertical {
            return CGSize(width: maxWidth, height: item.itemSize.height)
        }
        return item.itemSize
    }
    
    public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return items.count
    }
    
    public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ZLPopMenuCell", for: indexPath) as! ZLPopMenuCell
        let item = items[indexPath.row]
        cell.configure(with: item)
        
        return cell
    }
    
    public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        self.dismiss(animated: false) {
            let item = self.items[indexPath.row]
            item.callBack()
        }
    }
}

extension ZLPopMenu {
    
    private static func topViewController() -> UIViewController? {
        guard let rootViewController = UIApplication.shared.keyWindow?.rootViewController else {
            return nil
        }
        return topViewController(with: rootViewController)
    }
    
    private static func topViewController(with rootViewController: UIViewController) -> UIViewController {
        if let tabBarController = rootViewController as? UITabBarController {
            return topViewController(with: tabBarController.selectedViewController!)
        } else if let navigationController = rootViewController as? UINavigationController {
            return topViewController(with: navigationController.visibleViewController!)
        } else if let presentedViewController = rootViewController.presentedViewController {
            return topViewController(with: presentedViewController)
        }
        return rootViewController
    }
}

extension UIColor {
    convenience init(hex: String, alpha: CGFloat = 1.0) {
        var cString = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased()
        
        if cString.count < 6 {
            self.init(white: 0, alpha: 0)
            return
        }
        
        if cString.hasPrefix("0X") {
            cString = String(cString.dropFirst(2))
        }
        if cString.hasPrefix("#") {
            cString = String(cString.dropFirst())
        }
        
        if cString.count != 6 {
            self.init(white: 0, alpha: 0)
            return
        }
        
        var rgbValue: UInt64 = 0
        Scanner(string: cString).scanHexInt64(&rgbValue)
        
        self.init(red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
                  green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
                  blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
                  alpha: alpha)
    }
}
